---
title: React Router
description: Step-by-step guide to deploying a React Router (formerly Remix) application to Cloudflare Workers using Alchemy.
sidebar:
  order: 2
---

import { Tabs, TabItem } from '@astrojs/starlight/components';

This guide demonstrates how to deploy a [React Router](https://reactrouter.com/) (formerly Remix.js) application to Cloudflare with Alchemy.

## Init

Start by creating a new React Router project using Alchemy:

<Tabs syncKey="pkgManager">
  <TabItem label="bun">
    ```sh
    bunx alchemy create my-react-router-app --template=react-router
    cd my-react-router-app
    ```
  </TabItem>
  <TabItem label="npm">
    ```sh
    npx alchemy create my-react-router-app --template=react-router
    cd my-react-router-app
    ```
  </TabItem>
  <TabItem label="pnpm">
    ```sh
    pnpm dlx alchemy create my-react-router-app --template=react-router
    cd my-react-router-app
    ```
  </TabItem>
  <TabItem label="yarn">
    ```sh
    yarn dlx alchemy create my-react-router-app --template=react-router
    cd my-react-router-app
    ```
  </TabItem>
</Tabs>

## Login

Before you can deploy, you need to authenticate by running `alchemy login`.

<Tabs syncKey="pkgManager">
  <TabItem label="bun">
    ```sh
    bun alchemy login
    ```
  </TabItem>
  <TabItem label="npm">
    ```sh
    npx alchemy login
    ```
  </TabItem>
  <TabItem label="pnpm">
    ```sh
    pnpm alchemy login
    ```
  </TabItem>
  <TabItem label="yarn">
    ```sh
    yarn alchemy login
    ```
  </TabItem>
</Tabs>

::: tip
Alchemy will by default try and use your wrangler OAuth token and Refresh Token to connect but see the [Cloudflare](/guides/cloudflare) for other methods.

## Deploy

Now we can run and deploy our Alchemy stack:

<Tabs syncKey="pkgManager">
  <TabItem label="bun">
    ```sh
    bun run deploy
    ```
  </TabItem>
  <TabItem label="npm">
    ```sh
    npm run deploy
    ```
  </TabItem>
  <TabItem label="pnpm">
    ```sh
    pnpm run deploy
    ```
  </TabItem>
  <TabItem label="yarn">
    ```sh
    yarn run deploy
    ```
  </TabItem>
</Tabs>

It will log out the URL of your new React Router website hosted on Cloudflare:

```
{
  url: "https://website.${your-sub-domain}.workers.dev",
}
```

## Local

<Tabs syncKey="pkgManager">
  <TabItem label="bun">
    ```sh
    bun run dev
    ```
  </TabItem>
  <TabItem label="npm">
    ```sh
    npm run dev
    ```
  </TabItem>
  <TabItem label="pnpm">
    ```sh
    pnpm run dev
    ```
  </TabItem>
  <TabItem label="yarn">
    ```sh
    yarn run dev
    ```
  </TabItem>
</Tabs>

## Destroy

For illustrative purposes, let's destroy the Alchemy stack:

<Tabs syncKey="pkgManager">
  <TabItem label="bun">
    ```sh
    bun run destroy
    ```
  </TabItem>
  <TabItem label="npm">
    ```sh
    npm run destroy
    ```
  </TabItem>
  <TabItem label="pnpm">
    ```sh
    pnpm run destroy
    ```
  </TabItem>
  <TabItem label="yarn">
    ```sh
    yarn run destroy
    ```
  </TabItem>
</Tabs>

## What files are created

### `.env`

Alchemy requires a locally set password to encrypt Secrets that are stored in state. Be sure to change this.

:::note
See the [Secret](/concepts/secret) documentation to learn more.
:::

```
ALCHEMY_PASSWORD=change-me
```

### `alchemy.run.ts`

The `alchemy.run.ts` file contains your infrastructure setup:

```typescript
import alchemy from "alchemy";
import { ReactRouter } from "alchemy/cloudflare";

const app = await alchemy("my-react-router-app");

export const worker = await ReactRouter("website");

console.log({
  url: worker.url,
});

await app.finalize();
```

### `types/env.d.ts`

The `types/env.d.ts` file provides type-safe access to Cloudflare bindings:

```typescript
// This file infers types for the cloudflare:workers environment from your Alchemy Worker.
// @see https://alchemy.run/concepts/bindings/#type-safe-bindings

import type { worker } from "../alchemy.run.ts";

export type CloudflareEnv = typeof worker.Env;

declare global {
  type Env = CloudflareEnv;
}

declare module "cloudflare:workers" {
  namespace Cloudflare {
    export interface Env extends CloudflareEnv {}
  }
}
```

### `tsconfig.node.json`

The CLI updated the `tsconfig.node.json` to include `alchemy.run.ts` and register `@cloudflare/workers-types` + `types/env.d.ts` globally

:::tip
The `alchemy.run.ts` script will be run by `node` but still needs to infer the [Binding](/concepts/bindings) types which depends on `@cloudflare/workers-types`:
:::

```json
{
  "extends": "./tsconfig.json",
  "include": [
    "vite.config.ts",
    // ensure our types and alchemy.run.ts are included
    "types/**/*.ts",
    "alchemy.run.ts"
  ],
  "compilerOptions": {
    "composite": true,
    "strict": true,
    // register cloudflare types and our Env types globally
    "types": ["@cloudflare/workers-types", "./types/env.d.ts"],
    "lib": ["ES2022"],
    "target": "ES2022",
    "module": "ES2022",
    "moduleResolution": "bundler"
  }
}
``` 
### `vite.config.ts`

Use the `alchemy()` function to develop and deploy for Cloudflare Workers:

```ts
import { reactRouter } from "@react-router/dev/vite";
import alchemy from "alchemy/cloudflare/react-router";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig({
  plugins: [
    alchemy(),
    reactRouter(),
    tsconfigPaths({
      root: "."
    }),
  ],
});
```